﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace UNSWThinkDBTool
{
   /// <summary>
   /// Main windows form that is run when application is initialised.
   /// HELP!! LET ME OUT OF HERE!!
   /// </summary>
   public partial class MainForm : Form
   {
      private DBConnection dbConnection;
      private bool connected;
      private ArrayList tableNames;
      private LoadingForm loading;
      private ArrayList backupDataCells;
      private object oldValue;

      /// <summary>
      /// Default constructor for MainForm.
      /// </summary>
      public MainForm()
      {
         InitializeComponent();

         connected = false;
         oldValue = new Object();
         tabControl1.TabPages.Clear();
         deleteRowToolStripButton.Enabled = false;
      }

      private void connectToolStripMenuItem_Click(object sender, EventArgs e)
      {
         if (connected)
         {
            string confirmMessage = "Are you sure you want to disconnect from '" + dbConnection.DatabaseName + "' @ " + dbConnection.ServerAddress + " on port " + dbConnection.ServerPort;
            DialogResult result = MessageBox.Show(confirmMessage, "Confirm disconnect", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            if (result == DialogResult.Yes)
            {
               dbConnection.Disconnect();
               connected = false;
               ToggleConnectMenuLabel();
               tabControl1.TabPages.Clear();
            }
         }
         else
         {
            ConnectForm connForm = new ConnectForm(this);
            DialogResult result = connForm.ShowDialog();

            if (result == DialogResult.OK)
            {
               loading = new LoadingForm();
               loading.Show();

               connectBackgroundWorker.RunWorkerAsync();
            }
         }
      }

      /// <summary>
      /// Dynamically create TabPages(s) with DataGridView(s).
      /// </summary>
      private void CreateTabPages()
      {
         foreach (string tableName in tableNames)
         {
            DataTable dTable = dbConnection.GetTableData(tableName);

            DataGridView tempGridView = new DataGridView();
            tempGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            tempGridView.Dock = System.Windows.Forms.DockStyle.Fill;
            tempGridView.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
            tempGridView.Location = new System.Drawing.Point(3, 3);
            tempGridView.Name = tableName + "DataGridView";
            tempGridView.Size = new System.Drawing.Size(778, 510);
            tempGridView.TabIndex = 0;
            //tempGridView.Columns = dbConnection.GetColumnNames(tableName);
            //tempGridView.Columns.AddRange(dbConnection.GetColumnNames(tableName));
            /*ArrayList columnHeaders = dbConnection.GetColumnNames(tableName);
            foreach (string columnHeader in columnHeaders)
            {
               tempGridView.Columns.Add(columnHeader, columnHeader);
            }*/
            tempGridView.DataSource = dTable;
            tempGridView.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(tempGridView_CellValueChanged);
            tempGridView.CellBeginEdit += new System.Windows.Forms.DataGridViewCellCancelEventHandler(tempGridView_CellBeginEdit);
            tempGridView.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(tempGridView_CellEndEdit);
            tempGridView.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(tempGridView_DataError);
            tempGridView.RowEnter += new System.Windows.Forms.DataGridViewCellEventHandler(tempGridView_RowEnter);
            tempGridView.UserDeletingRow += new System.Windows.Forms.DataGridViewRowCancelEventHandler(tempGridView_UserDeletingRow);

            TabPage tempTabPage = new TabPage();
            //tabControl1.Controls.Add(tempTabPage);
            ////tabControl1.TabPages.Add(tempTabPage);
            tempTabPage.Controls.Add(tempGridView);
            tempTabPage.Location = new System.Drawing.Point(4, 22);
            tempTabPage.Name = tableName + "TabPage";
            tempTabPage.Padding = new System.Windows.Forms.Padding(3);
            tempTabPage.Size = new System.Drawing.Size(784, 516);
            tempTabPage.TabIndex = 0;
            tempTabPage.Text = tableName;
            tempTabPage.UseVisualStyleBackColor = true;

            connectBackgroundWorker.ReportProgress(0, tempTabPage);

            /*
            ProgressItem pItem = new ProgressItem(tempTabPage, dTable);
            connectBackgroundWorker.ReportProgress(0, pItem);
             */
         }
      }

      /// <summary>
      /// Toggles the connectToolStripMenuItem text between "Connect" and "Disconnect."
      /// </summary>
      public void ToggleConnectMenuLabel()
      {
         if (connectToolStripMenuItem.Text == "Connect")
         {
            connectToolStripMenuItem.Text = "Disconnect";
         }
         else
         {
            connectToolStripMenuItem.Text = "Connect";
         }
      }

      /// <summary>
      /// Sets the DBConnection object that MainForm uses
      /// </summary>
      public DBConnection SetDBConnection
      {
         set
         {
            dbConnection = value;
         }
      }

      /// <summary>
      /// Gets or sets the connected global variable which is used to determine whether there
      /// is an active connection to a database.
      /// </summary>
      public bool Connected
      {
         get
         {
            return connected;
         }

         set
         {
            connected = value;
         }
      }

      /// <summary>
      /// Attempt to perform a disconnection from a connected database.
      /// </summary>
      private void AttpemtClose()
      {
         if (connected)
         {
            bool result = dbConnection.Disconnect();

            if (!result)
            {
               MessageBox.Show("Connection to database could not be closed properly", "Disconnect Problem", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
         }
      }

      private void exitToolStripMenuItem_Click(object sender, EventArgs e)
      {
         AttpemtClose();
         this.Close();
      }

      private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
      {
         AttpemtClose();
      }

      private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
      {
         AboutForm about = new AboutForm();
         about.Show();
      }

      private void tempGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
      {
         DataGridView tempGridView = (DataGridView) sender;
         
         int editedCellRow = e.RowIndex;
         int editedCellColumn = e.ColumnIndex;
         DataGridViewCell editedCell = tempGridView.Rows[editedCellRow].Cells[editedCellColumn];
         editedCell.Style.BackColor = Defs.EDIT_COLOUR;
         editedCell.Style.Font = new Font(dataGridView1.Font, FontStyle.Bold);
         //string msg = "You changed cell (" + editedCellColumn + "," + editedCellRow + ") with value " + editedCell.Value.ToString();
         //MessageBox.Show(msg);

         restoreToolStripButton.Enabled = true;
         commitToolStripButton.Enabled = true;
      }

      private void tempGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
      {
         commitToolStripButton.Enabled = false;
         restoreToolStripButton.Enabled = false;

         if (backupDataCells == null)
         {
            backupDataCells = new ArrayList();
         }

         DataGridView tempGridView = (DataGridView)sender;
         TabPage tempTabPage = (TabPage)tempGridView.Parent;

         int originalCellRow = e.RowIndex;
         int originalCellColumn = e.ColumnIndex;
         DataGridViewCell originalCell = tempGridView.Rows[originalCellRow].Cells[originalCellColumn];
         //MessageBox.Show(originalCell.Style.BackColor.ToString());

         BackupCell backup = new BackupCell(tempTabPage.Name, originalCellRow, originalCellColumn, originalCell.Value, originalCell.ValueType);
         backupDataCells.Add(backup);

         oldValue = originalCell.Value;
      }

      private void tempGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
      {
         DataGridView tempGridView = (DataGridView)sender;
         TabPage tempTabPage = (TabPage)tempGridView.Parent;

         int originalCellRow = e.RowIndex;
         int originalCellColumn = e.ColumnIndex;
         DataGridViewCell originalCell = tempGridView.Rows[originalCellRow].Cells[originalCellColumn];

         if (originalCell.Value.ToString() != oldValue.ToString())
         {
            commitToolStripButton.Enabled = true;
            restoreToolStripButton.Enabled = true;
         }
      }

      private void tempGridView_DataError(object sender, DataGridViewDataErrorEventArgs e)
      {
         if (e.Context.ToString().Contains(DataGridViewDataErrorContexts.Parsing.ToString()))
         {
            string msg = "Entered data is not in the correct format";
            MessageBox.Show(msg, "Parsing Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
         }
         else
         {
            MessageBox.Show(e.Exception.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
         }
      }

      private void tempGridView_RowEnter(object sender, DataGridViewCellEventArgs e)
      {
         DataGridView dgv = (DataGridView)sender;
         if (dgv.SelectedRows.Count > 0)
         {
            deleteRowToolStripButton.Enabled = true;
         }
         else
         {
            deleteRowToolStripButton.Enabled = false;
         }
      }

      private void tempGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
      {
         DataGridView tempGridView = (DataGridView)sender;
         TabPage tempTabPage = (TabPage)tempGridView.Parent;
         string tableName = tempTabPage.Text;
         DataGridViewRow row = e.Row;
         
         int id = (int) row.Cells["id"].Value;

         bool successfulDelete = dbConnection.DeleteRecord(tableName, id);

         if (!successfulDelete)
         {
            e.Cancel = true;
         }
      }

      private void connectBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
      {
         //backupDataTables = new ArrayList();
         tableNames = dbConnection.GetTableNames();

         CreateTabPages();
      }

      private void connectBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
      {
         loading.Close();
      }

      private void connectBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
      {
         TabPage tempTabPage = (TabPage)e.UserState;
         tabControl1.Controls.Add(tempTabPage);
         /*
         ProgressItem pItem = (ProgressItem)e.UserState;
         tabControl1.Controls.Add(pItem.NewTabPage);

         if (backupDataTables == null)
         {
            backupDataTables = new ArrayList();
         }
         backupDataTables.Add(pItem.NewDataTable);
          */
      }

      private void restoreToolStripButton_Click(object sender, EventArgs e)
      {
         string msg = "Any edits to the data that you have made will be lost." +
            "\n\nContinue with the restore process?";
         DialogResult result = MessageBox.Show(msg, "Confirm restore?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

         if (result == DialogResult.Yes)
         {
            for (int i = (backupDataCells.Count - 1); i >= 0; i--)
            {
               BackupCell tempBackCell = (BackupCell) backupDataCells[i];

               TabPage tempTabPage = LocateTabPage(tempBackCell.TabPageName);
               foreach (Control con in tempTabPage.Controls)
               {
                  if (con.GetType() == typeof(DataGridView))
                  {
                     DataGridView dgv = (DataGridView)con;
                     DataGridViewCell tempCell = dgv.Rows[tempBackCell.RowIndex].Cells[tempBackCell.ColumnIndex];

                     tempCell.Value = tempBackCell.Value;
                     tempCell.Style.BackColor = Defs.NORMAL_COLOUR;
                     tempCell.Style.Font = new Font(dataGridView1.Font, FontStyle.Regular);

                     backupDataCells.RemoveAt(backupDataCells.Count - 1);
                  }
               }
            }

            restoreToolStripButton.Enabled = false;
            commitToolStripButton.Enabled = false;
         }
      }

      private TabPage LocateTabPage(string tabName)
      {
         TabPage tempTabPage = new TabPage();
         foreach (TabPage tp in tabControl1.TabPages)
         {
            if (tp.Name == tabName)
            {
               tempTabPage = tp;
            }
         }
         return tempTabPage;
      }

      private void commitToolStripButton_Click(object sender, EventArgs e)
      {
         string msg = "Any edits to the data that you have made will be updated to the database." +
            "\n\nContinue with the commit process?";
         DialogResult result = MessageBox.Show(msg, "Confirm commit?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

         if (result == DialogResult.Yes)
         {
            foreach (TabPage tp in tabControl1.TabPages)
            {
               string tabName = tp.Text;
               foreach (Control con in tp.Controls)
               {
                  if (con.GetType() == typeof(DataGridView))
                  {
                     DataGridView dgv = (DataGridView)con;

                     for (int i = 0; i < dgv.Rows.Count; i++)
                     {
                        for (int j = 0; j < dgv.Rows[i].Cells.Count; j++)
                        {
                           DataGridViewCell tempCell = dgv.Rows[i].Cells[j];
                           if (tempCell.Style.BackColor == Defs.EDIT_COLOUR)
                           {
                              string idValue = dgv.Rows[i].Cells["id"].Value.ToString();
                              if (idValue != String.Empty)
                              {
                                 int recordID = int.Parse(dgv.Rows[i].Cells["id"].Value.ToString());
                                 string columnName = tempCell.OwningColumn.Name;

                                 //string test = String.Format("Table Name: {0}\nRecord: {1}\nColumn Name: {2}", tabName, recordID, columnName);
                                 //MessageBox.Show(test);
                                 bool success = dbConnection.UpdateSingleColumn(tabName, columnName, recordID, tempCell.Value);

                                 if (success)
                                 {
                                    tempCell.Style.BackColor = Defs.NORMAL_COLOUR;
                                    tempCell.Style.Font = new Font(dataGridView1.Font, FontStyle.Regular);
                                 }
                                 else
                                 {
                                    msg = "The database could not successfully update with values:\n" +
                                       "Table Name: " + tabName + "\n" +
                                       "ID No.: " + recordID + "\n" +
                                       "Column Name: " + columnName + "\n" +
                                       "Value: " + tempCell.Value.ToString();
                                    MessageBox.Show(msg, "Update not successful", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                 }
                              }
                              else
                              {
                                 // TODO: Peform insert

                                 bool recordComplete = CheckRowCompleted(dgv.Rows[i]);

                                 if (recordComplete)
                                 {
                                    string columnName = tempCell.OwningColumn.Name;
                                    
                                    string[] columnNames;
                                    object[] values;
                                    int startIndex = 0;
                                    if (dgv.Columns[0].HeaderText != "id")
                                    {
                                       columnNames = new string[dgv.Columns.Count];
                                       values = new object[dgv.Columns.Count];
                                    }
                                    else
                                    {
                                       columnNames = new string[dgv.Columns.Count - 1];
                                       values = new object[dgv.Columns.Count - 1];
                                       startIndex = 1;
                                    }

                                    for (int k = startIndex; k < (columnNames.Length + startIndex); k++) 
                                    {
                                       if (columnNames.Length < dgv.Columns.Count)
                                       {
                                          columnNames[k - 1] = dgv.Columns[k].HeaderText;
                                       }
                                       else
                                       {
                                          columnNames[k] = dgv.Columns[k].HeaderText;
                                       }
                                    }

                                    for (int k = startIndex; k < (values.Length + startIndex); k++) 
                                    {
                                       if (columnNames.Length < dgv.Columns.Count)
                                       {
                                          values[k - 1] = dgv.Rows[i].Cells[k].Value;
                                          //string temp = "k = " + k + "\nvalues: " + values[k - 1].ToString();
                                          //MessageBox.Show(temp);
                                       }
                                       else
                                       {
                                          values[k] = dgv.Rows[i].Cells[k].Value;
                                          //string temp = "k = " + k + "\nvalues: " + values[k].ToString();
                                          //MessageBox.Show(temp);
                                       }
                                    }

                                    // Perform single row insert, return id, and insert into id cell
                                    int returningID = dbConnection.InsertRecord(tabName, columnNames, values);

                                    if (returningID > 0)
                                    {
                                       DataTable dt = (DataTable)dgv.DataSource;
                                       dt.Columns["id"].ReadOnly = false;
                                       dt.Rows[i]["id"] = returningID;
                                       dt.Columns["id"].ReadOnly = true;
                                       ClearRowStyling(dgv.Rows[i]);
                                    }
                                    else
                                    {
                                       msg = "The new record could not be inserted into the database\n";
                                       MessageBox.Show(msg, "Update not successful", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    }
                                 }
                                 else
                                 {
                                    msg = "One of the newly added records has not been fully completed\n";
                                    MessageBox.Show(msg, "Record not complete", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                 }

                                 i++;
                                 j = 0;
                              }
                           }
                        }
                     }
                  }
               }
            }

            restoreToolStripButton.Enabled = false;
            commitToolStripButton.Enabled = false;
         }
      }

      private bool CheckRowCompleted(DataGridViewRow row)
      {
         bool result = false;
         int filledCellCounter = 0;

         foreach (DataGridViewCell tempCell in row.Cells)
         {
            if (tempCell.OwningColumn.Name != "id")
            {
               if (tempCell.Value.ToString() != String.Empty)
               {
                  filledCellCounter++;
               }
            }
         }

         // fix for case where table does not contain id column
         if (filledCellCounter == (row.Cells.Count - 1))
         {
            result = true;
         }

         return result;
      }

      private void ClearRowStyling(DataGridViewRow row)
      {
         foreach (DataGridViewCell tempCell in row.Cells)
         {
            tempCell.Style.BackColor = Defs.NORMAL_COLOUR;
            tempCell.Style.Font = new Font(dataGridView1.Font, FontStyle.Regular);
         }
      }

      private void deleteRowToolStripButton_Click(object sender, EventArgs e)
      {
         if (dataGridView1.SelectedRows.Count > 0)
         {
            string msg = "Are you sure you want to delete selected record?";
            DialogResult result = MessageBox.Show(msg, "Confirm delete?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (result == DialogResult.Yes)
            {
               TabPage tempTabPage = (TabPage)dataGridView1.Parent;
               string tableName = tempTabPage.Text;

               MessageBox.Show(dataGridView1.SelectedRows.Count.ToString());
               DataGridViewRow selectedRow = dataGridView1.SelectedRows[0];
               int selectedIndex = selectedRow.Index;

               int id = (int)selectedRow.Cells["id"].Value;

               bool successfulDelete = dbConnection.DeleteRecord(tableName, id);

               if (!successfulDelete)
               {
                  dataGridView1.Rows.RemoveAt(selectedIndex);
               }
            }
         }
      }
   }
}
